﻿using AutoMapper;
using Furion;
using Furion.DependencyInjection;
using Furion.DistributedIDGenerator;
using Furion.LinqBuilder;
using Microsoft.EntityFrameworkCore;
using System.Security.Claims;
using StackExchange.Profiling.Internal;
using XinGuanERP.Utils;
using XinGuanERP.Db;
using XinGuanERP.Enums.system;
using XinGuanERP.Constants.system;
using XinGuanERP.Models.Po.system;
using XinGuanERP.Models.Vo.system;
using XinGuanERP.Services.system.IServices;

namespace XinGuanERP.Services.system
{
    public class SysMenuService : ISysMenuService, ITransient
    {
        private readonly DefaultDbContext _defaultDbContext;

        public SysMenuService(DefaultDbContext defaultDbContext)
        {
            _defaultDbContext = defaultDbContext;
        }

        public bool DeleteSysMenu(string Id)
        {
            var res = _defaultDbContext.SysMenus.FirstOrDefault(t => t.Id == Id);
            if (res != null)
            {
                _defaultDbContext.SysMenus.Remove(res);
                return _defaultDbContext.SaveChanges() > 0;
            }
            else
            {
                return false;
            }
        }

        public PageResult<SysMenuVo> GetSysMenuWithPage(int page, int pageSize, string? menuName, string? nodeId)
        {
            var res = new List<SysMenu>();
            var count = 0;
            var sql = _defaultDbContext.SysMenus.OrderBy(t => t.Sort).AsQueryable();
            if (!nodeId.IsNullOrWhiteSpace())
            {
                sql = sql.Where(t => t.ParentId == nodeId).AsQueryable();
            }
            else
            {
                sql = sql.Where(t => t.ParentId == null).AsQueryable();
            }
            if (!menuName.IsNullOrEmpty())
            {
                res = sql.Where(t => EF.Functions.Like(t.MenuName, "%" + menuName + "%"))
                    .Skip((page - 1) * pageSize).Take(pageSize).ToList();
                count = sql.Where(t => EF.Functions.Like(t.MenuName, "%" + menuName + "%")).Count();
            }
            else
            {
                res = sql.Skip((page - 1) * pageSize).Take(pageSize).ToList();
                count = sql.Count();
            }

            var viewSysMenus = new List<SysMenuVo>();
            var config = new MapperConfiguration(cfg => cfg.CreateMap<SysMenu, SysMenuVo>());
            var mapper = config.CreateMapper();
            foreach (var sysMenu in res)
            {
                viewSysMenus.Add(mapper.Map<SysMenu, SysMenuVo>(sysMenu));
            }

            return new PageResult<SysMenuVo>()
            {
                Items = viewSysMenus,
                Total = count
            };
        }

        public SysMenuVo GetSysMenuById(string Id)
        {
            var res = _defaultDbContext.SysMenus.FirstOrDefault(t => t.Id == Id);
            var config = new MapperConfiguration(cfg => cfg.CreateMap<SysMenu, SysMenuVo>());
            var mapper = config.CreateMapper();
            return mapper.Map<SysMenu, SysMenuVo>(res);
        }

        public List<SysMenuListVo> GetSysMenuWithTree()
        {
            var res = _defaultDbContext.SysMenus.OrderBy(t => t.Sort).ToList();
            var viewSysMenus = new List<SysMenuListVo>();
            foreach (var item in res)
            {
                if (item.ParentId != null)
                {
                    continue;
                }

                var viewSysMenu = new MapperConfiguration(cfg => cfg.CreateMap<SysMenu, SysMenuListVo>()
                        .BeforeMap((src, des) => des.Children = BuildSysMenuTree(item, res)))
                    .CreateMapper().Map<SysMenuListVo>(item);
                viewSysMenus.Add(viewSysMenu);
            }

            return viewSysMenus;
        }

        public List<SysMenuListVo> BuildSysMenuTree(SysMenu sysMenu, List<SysMenu> sysMenus)
        {
            var children = new List<SysMenuListVo>();
            foreach (var item in sysMenus)
            {
                if (item.ParentId != null && item.ParentId.Equals(sysMenu.Id))
                {
                    var viewSysMenu = new MapperConfiguration(cfg => cfg.CreateMap<SysMenu, SysMenuListVo>()
                            .BeforeMap((src, des) => des.Children = BuildSysMenuTree(item, sysMenus)))
                        .CreateMapper().Map<SysMenuListVo>(item);
                    children.Add(viewSysMenu);
                }
            }

            if (children.Count == 0)
            {
                return new List<SysMenuListVo>();
            }

            return children;
        }

        public bool UpdateSysMenu(SysMenuVo viewSysMenu)
        {
            var res = _defaultDbContext.SysMenus.FirstOrDefault(t => t.Id == viewSysMenu.Id);
            var config = new MapperConfiguration(cfg => cfg.CreateMap<SysMenuVo, SysMenu>()
                .BeforeMap((src, des) => src.Id = Guid.NewGuid().ToString().Replace("-", "").ToUpper())
                .BeforeMap((src, des) => des.CreateTime = DateTime.Now)
                .BeforeMap((src, des) => des.CreateUserId = App.User?.FindFirstValue("UserId"))
                .BeforeMap((src, des) => des.CreateUserName = App.User?.FindFirstValue("UserName")));
            var mapper = config.CreateMapper();
            if (res == null)
            {
                _defaultDbContext.SysMenus.Add(
                    mapper.Map<SysMenu>(viewSysMenu)
                );
            }
            else
            {
                res = new MapperConfiguration(cfg => cfg.CreateMap<SysMenuVo, SysMenu>()
                        .BeforeMap((src, des) => des.UpdateTime = DateTime.Now)
                        .BeforeMap((src, des) => des.UpdateUserId = App.User?.FindFirstValue("UserId"))
                        .BeforeMap((src, des) => des.UpdateUserName = App.User?.FindFirstValue("UserName")))
                    .CreateMapper().Map(viewSysMenu, res);
            }

            return _defaultDbContext.SaveChanges() > 0;
        }

        public List<RouteItemVo> GetGrantMenuWithList()
        {
            var sysMenuList = new List<SysMenu>();
            var sysRoleMenuList = _defaultDbContext.SysRoleMenus.Where(t => t.RoleId == App.User.FindFirstValue("RoleId"))
                .ToList();
            var sysMenuIds = sysRoleMenuList.Select(t => t.MenuId).Distinct().ToList();
            sysMenuList = _defaultDbContext.SysMenus
                .Where(t => sysMenuIds.Contains(t.Id))
                .Where(t => t.Status.Equals(StatusEnum.YES.Code))
                .Where(t => new string[] { MenuTypeEnum.DIR.Code, MenuTypeEnum.MENU.Code }.Contains(t.MenuType))
                .ToList();
            var routeItemVOList = sysMenuList.Where(t => t.ParentId == null)
                .OrderBy(t => t.Sort)
                .Select(t =>
            {
                var node = ConvertToRoute(t);
                node.Children = GetChildrenList(t, sysMenuList);
                return node;
            }).ToList();
            return routeItemVOList;
        }

        public List<SysMenuListVo> GetSysMenuAndExcludeNodeWithOptionTree(string? nodeId)
        {
            var sysMenuList = new List<SysMenu>();
            if (!nodeId.IsNullOrEmpty())
            {
                sysMenuList = _defaultDbContext.SysMenus.Where(t => t.Id != nodeId).ToList();
            }
            else
            {
                sysMenuList = _defaultDbContext.SysMenus.ToList();
            }

            var viewSysMenus = new List<SysMenuListVo>();
            foreach (var item in sysMenuList)
            {
                if (item.ParentId != null)
                    continue;

                var viewSysMenu = new MapperConfiguration(cfg => cfg.CreateMap<SysMenu, SysMenuListVo>()
                        .BeforeMap((src, des) => des.Children = BuildSysMenuTree(item, sysMenuList)))
                    .CreateMapper().Map<SysMenuListVo>(item);
                viewSysMenus.Add(viewSysMenu);
            }
            return viewSysMenus;
        }

        private List<RouteItemVo> GetChildrenList(SysMenu root, List<SysMenu> list)
        {
            //if ()
            var childrenList = list.Where(t => t.ParentId != null && t.ParentId.Equals(root.Id)).OrderBy(t => t.Sort).Select(t =>
            {
                var node = ConvertToRoute(t);
                node.Children = GetChildrenList(t, list);
                return node;
            }).ToList();
            return childrenList;
        }

        private RouteItemVo ConvertToRoute(SysMenu item)
        {
            var node = new RouteItemVo()
            {
                Name = StrUtil.FirstCharToUpper(item.RoutePath),
                Path = item.RoutePath,
                Component = item.Component
            };
            // 一级目录
            if (item.MenuType.Equals(MenuTypeEnum.DIR.Code) && item.ParentId == null)
            {
                node.Path = "/" + item.RoutePath;
                node.Component = MenuConstant.LAYOUT;
            }

            // 外部链接
            if (item.MenuType.Equals(MenuTypeEnum.MENU.Code) &&
                item.LinkExternal.Equals(LinkExternalEnum.YES.Code))
            {
                node.Component = MenuConstant.IFRAME;
            }

            var viewRouteMeta = new RouteMetaVo()
            {
                Title = item.MenuName,
                Icon = item.Icon,
                HideMenu = !string.IsNullOrWhiteSpace(item.Visible) &&
                           item.Visible.Equals(VisibleEnum.HIDE.Code)
            };
            // 菜单
            if (item.MenuType.Equals(MenuTypeEnum.MENU.Code))
            {
                viewRouteMeta.IgnoreKeepAlive = item.KeepAlive.Equals(KeepAliveEnum.YES.Code);
            }

            // 外部链接
            if (item.MenuType.Equals(MenuTypeEnum.MENU.Code) &&
                item.LinkExternal.Equals(LinkExternalEnum.YES.Code))
            {
                // 内嵌
                if (item.Frame.Equals(FrameEnum.YES.Code))
                {
                    viewRouteMeta.FrameSrc = item.LinkUrl;
                }

                // 外嵌
                if (item.Frame.Equals(FrameEnum.NO.Code))
                {
                    node.Path = item.LinkUrl;
                }
            }

            node.Meta = viewRouteMeta;
            return node;
        }

        public HashSet<string> GetGrantPermissions()
        {
            // 查询按钮菜单权限标识
            var sysRoleMenuList = _defaultDbContext.SysRoleMenus.Where(t => t.RoleId == App.User.FindFirstValue("RoleId"))
                .ToList();
            if (sysRoleMenuList.IsNullOrEmpty())
            {
                return new HashSet<string>();
            }
            // 查询菜单
            var menuIds = sysRoleMenuList.Select(t => t.MenuId).ToHashSet();
            var sysMenuList = _defaultDbContext.SysMenus.Where(t => t.MenuName != null && t.MenuType != null && t.MenuType.Equals(MenuTypeEnum.BUTTON.Code) &&
                                                                  t.Status.Equals(StatusEnum.YES.Code) && menuIds.Contains(t.Id)).ToList();
            return sysMenuList.Select(t => t.Permission).ToHashSet()!;
        }
    }
}
